﻿using PBO.Data;
using PBO.Game.BattleLog;
using PBO.Network;
using PBO.Network.Enumerations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PBO.Game.BattleClass
{
    public class BattleGroup
    {
        public Battle Battle { get; private set; }
        public List<BattleTeam> Teams { get; private set; }
        ILogBuilder log { get { return this.Battle.log; } }
        public BattleGroup Opponent { get; internal set; }

        public BattleGroup(Battle battle)
        {
            this.Battle = battle;
            this.Teams = new List<BattleTeam>();
        }

        public void AddTeam(int id, string name, TeamData team)
        {
            var t = new BattleTeam(this, id, name, team);
            this.Teams.Add(t);
        }

        #region IEnumerable

        /// <summary>
        /// 当前在场的pokemon
        /// </summary>
        public IEnumerable<Pokemon> SelectedPokemon
        {
            get
            {
                return from t in Teams from pm in t.SelectedPokemon select pm;
            }
        }

        /// <summary>
        /// 此组所有Pokemon
        /// </summary>
        public IEnumerable<Pokemon> AllPokemon
        {
            get
            {
                return from t in Teams from pm in t.Pokemons where pm != null select pm;
            }
        }

        public IEnumerable<Pokemon> AlivePokemons
        {
            get
            {
                return this.AllPokemon.Where(p => p.HealthPower > 0);
            }
        }

        public int AlivePokemonsCount
        {
            get
            {
                return this.AlivePokemons.Count();
            }
        }

        public IEnumerable<Pokemon> AliveSelectedPokemon
        {
            get
            {
                return this.SelectedPokemon.Where(p => p != null && p.HealthPower > 0);
            }
        }

        public IEnumerable<int> GetAllMoveId(Pokemon except)
        {
            return from p in this.AllPokemon
                   where !object.ReferenceEquals(p, except)
                   from m in p.GetSelMoves()
                   select m.Data.Id;
        }

        public bool NoPM
        {
            get { return this.AlivePokemonsCount == 0; }
        }

        #endregion

        /// <summary>
        /// 0 - 5 , 6 - 11
        /// </summary>
        public Pokemon GetPokemonByIndex(int index)
        {
            int tid = index / 6;
            int pid = index % 6;
            return this.Teams[tid].Pokemons[pid];
            //if (index < 6)
            //{
            //    return this.Teams[0].Pokemons[index];
            //}
            //else
            //{
            //    return this.Teams[1].Pokemons[index - 6];
            //}
        }

        public void ChangePokemon(Pokemon pm, int changeTo, bool pass)
        {
            var p2 = GetPokemonByIndex(changeTo);
            if (p2 != null && pm != p2 && pm.MyTeam == p2.MyTeam)
            {
                ChangePM(pm, p2, pass);
            }
        }

        public void ChangePM(Pokemon p1, Pokemon p2, bool pass)
        {
            if (pass && p1.GetSelTrait() == Trait.SuctionCups)
                pass = false;

            log.AppendMsg("Withdraw", p1.MyTeam.PlayerName, p1.NickName + "(" + p1.NameBase + ")");
            //log.AddText(GetPlayerName(withdraw) + "收回了" + withdraw.NickName + "(" + withdraw.NameBase + ")！");

            p1.lastMoveIndex = 0;
            if (p1.GetSelTrait() == Trait.NaturalCure)
                p1.RaiseTrait();
            if (p1.UsedItem.IsChoiceItem())
                p1.UsedItem = Item.None;

            foreach (var move in p1.GetSelMoves())
            {
                move.ResetUsed();
            }

            //跟我来 
            if (object.ReferenceEquals(Battle.Ground.followPokemon, p1))
                Battle.Ground.followPokemon = null;

            if (!pass || p1.BattleState.uTurn)
            {
                Battle.Ground.waterSport = false;
                Battle.Ground.mudSport = false;
            }
            //接力无法接束缚
            foreach (Pokemon pm in Opponent.SelectedPokemon.Where(p => p.BattleState.constraint))
            {
                if (pm.BattleState.constraintBy == PokemonIndex.Pokemon1OfTeam1 || pm.BattleState.constraintBy == PokemonIndex.Pokemon1OfTeam2)
                {
                    if (object.ReferenceEquals(p1, this.Teams[0].SelectedPokemon.First()))
                    {
                        pm.BattleState.constraint = false;
                    }
                }
                else if (object.ReferenceEquals(p1, this.Teams[1].SelectedPokemon.First()))
                {
                    pm.BattleState.constraint = false;
                }
            }
            foreach (Pokemon pm in Opponent.SelectedPokemon)
            {
                if (pm.BattleState.captivated && object.ReferenceEquals(pm.BattleState.captivateTarget, p1))
                {
                    pm.BattleState.captivated = false;
                    pm.BattleState.captivateTarget = null;
                }
            }

            PokemonBattleState battleState = new PokemonBattleState();
            var _with2 = p1.BattleState;
            if (_with2.wished && _with2.wishTurn != 1)
            {
                battleState.wished = true;
                battleState.wishTurn = _with2.wishTurn;
                //battleState.wishRecovery = _with2.wishRecovery;
            }
            if (_with2.futureAtk && _with2.futureCounter != 3)
            {
                battleState.futureAtk = true;
                battleState.futureCounter = _with2.futureCounter;
                battleState.futureAtkAcc = _with2.futureAtkAcc;
                battleState.futureDamage = _with2.futureDamage;
                //battleState.futureAtkValue = _with2.futureAtkValue;
                //battleState.futureAtkType = _with2.futureAtkType;
                //battleState.futureAtkMoveType = _with2.futureAtkMoveType;
                //battleState.futureAtkDamageRevision = _with2.futureAtkDamageRevision;
            }
            battleState.healwish = _with2.healwish;
            battleState.lunarDance = _with2.lunarDance;
            //接力
            if (pass && !p1.BattleState.uTurn)
            {
                battleState.PassCopy(p1.BattleState);
            }
            //睡眠计数器重置
            if (p1.sleepTurn != 0)
            {
                p1.sleepCounter = 0;
                if (p1.hypnosis)
                {
                    p1.sleepCounter = this.Battle._random.Next(Battle.MinSleepTurn, Battle.MaxSleepTurn + 1);
                }
            }
            p1.BattleState = null;
            ChangeSelectedPokemon(p1, p2);
            ShowPokemon(p2, battleState);
        }

        private void ChangeSelectedPokemon(Pokemon p1, Pokemon p2)
        {
            p1.MyTeam.SwapPokemon(p1, p2);
            if (!p1.MyTeam.SelectedPokemon.Contains(p1))
            {
                RemovePokemonHandler(p1);
            }
            if (p2.MyTeam.SelectedPokemon.Contains(p2))
            {
                AddPokemonHandler(p2);
            }
        }

        private void ShowPokemon(Pokemon pm, PokemonBattleState battleState)
        {
            pm.BattleState = battleState;

            log.AppendMsg("SendOut1", pm.MyTeam.PlayerName, pm.NickName + "(" + pm.NameBase + ")");
            //log.AddText(GetPlayerName(pm) + "换上了" + pm.NickName + "(" + pm.NameBase + ")！");
            if (PokemonChanged != null)
            {
                PokemonChanged(pm, EventArgs.Empty);
            }

            this.Battle.Ground.ChangeWeather(pm);

            if (pm.GetSelTrait() != Trait.MagicGuard && pm.HealthPower > 0)
            {
                if (!(pm.HaveType(BattleType.Flying) || pm.GetSelTrait() == Trait.Levitate || pm.BattleState.suspension) || this.Battle.Ground.Gravity || pm.GetItem() == Item.IronBall)
                {
                    if (poisonSpikesCounter > 0)
                    {
                        if (pm.HaveType(BattleType.Poison))
                        {
                            poisonSpikesCounter = 0;
                        }
                        else if (!pm.HaveType(BattleType.Steel))
                        {
                            switch (poisonSpikesCounter)
                            {
                                case 1:
                                    pm.SetState(PokemonState.Poison, null, false, true);
                                    break;
                                case 2:
                                    pm.SetState(PokemonState.Toxin, null, false, true);
                                    break;
                            }
                        }
                    }

                    if (spikesCounter > 0)
                    {
                        log.AppendMsg("Spikes", pm.NickName);
                        //log.AppendText(pm.NickName + "受到了钉子的伤害");
                        pm.HurtFraction(10 - spikesCounter * 2);
                    }
                }
                if (pm.HealthPower == 0) return;
                if (hideRockCounter == 1)
                {
                    log.AppendMsg("StealthRock", pm.NickName);
                    //log.AppendText(pm.NickName + "受到了隐蔽沙砾的伤害");
                    double typeEff = BattleType.Rock.EffectRevise(pm.Type1, pm.Type2);
                    pm.HurtFraction((int)(8 / typeEff));
                }
            }
            if (pm.HealthPower == 0) return;

            if (battleState.healwish)
            {
                log.AppendMsg("HealingWish", pm.NickName);
                //log.AddText(pm.NickName + "恢复了HP和状态！");
                pm.HPRecoverFraction(1);
                pm.State = PokemonState.No;
                battleState.healwish = false;
            }
            if (battleState.lunarDance)
            {
                log.AppendMsg("LunarDance", pm.NickName);
                //log.AddText(pm.NickName + "恢复了HP,PP和状态！");
                pm.HPRecoverFraction(1);
                pm.State = PokemonState.No;
                battleState.lunarDance = false;
                foreach (var move in pm.GetSelMoves())
                {
                    move.PP = move.MaxPP;
                }
            }
            pm.Showed();
            battleState.moved = true;
            //battleState.swaped = true;
        }

        public void EndTurnCount()
        {
            if (Reflect) reflectCounter--;
            if (LightScreen) lightScreenCounter--;
            if (Safeguard) safeguardCounter--;
            if (Mist) mistCounter--;
            if (WithWind) withWindCounter--;
            if (LuckyChant) luckyChantCounter--;
            if (moor) moorCounter--;
            if (flameSea) flameSeaCounter--;
            if (rainbow) rainbowCounter--;

            quickDefence = false;
            wideDefence = false;

            if (Reflect && reflectCounter == 0)
            {
                this.Reflect = false;
                log.AppendMsg("DeReflect", PlayerName);
                //log.AddText(PlayerName + "队伍的反射盾消失了！");
            }
            if (LightScreen && lightScreenCounter == 0)
            {
                this.LightScreen = false;
                log.AppendMsg("DeLightScreen", PlayerName);
                //log.AddText(PlayerName + "队伍的光墙消失了！");
            }
            if (Safeguard && safeguardCounter == 0)
            {
                this.Safeguard = false;
                log.AppendMsg("DeSafeguard", PlayerName);
                //log.AddText(PlayerName + "队伍的保护罩消失了！");
            }
            if (Mist && mistCounter == 0)
            {
                this.Mist = false;
                log.AppendMsg("DeMist", PlayerName);
                //log.AddText("覆盖在" + PlayerName + "队伍上的雾消失了！");
            }
            if (WithWind && withWindCounter == 0)
            {
                this.WithWind = false;
                log.AppendMsg("DeTailwind", PlayerName);
                //log.AddText(PlayerName + "队伍的顺风解除了！");
            }
            if (LuckyChant && luckyChantCounter == 0)
            {
                this.LuckyChant = false;
                log.AppendMsg("DeLuckyChant", PlayerName);
                //log.AddText(PlayerName + "队伍的祈福无效了！");
            }
            foreach (Pokemon pm in SelectedPokemon)
            {
                if (pm.BattleState.wished)
                    pm.BattleState.wishTurn += 1;
                if (pm.BattleState.futureAtk)
                    pm.BattleState.futureCounter += 1;
            }

            IsPokemonDiedLastTurn = IsPokemonDiedThisTurn;
            IsPokemonDiedThisTurn = false;
        }

        #region walls

        private int reflectCounter;
        private int lightScreenCounter;
        private int safeguardCounter;
        private int mistCounter;
        private int luckyChantCounter;
        private int withWindCounter;

        public int spikesCounter;
        public int hideRockCounter;
        public int poisonSpikesCounter;

        public bool quickDefence;

        public bool wideDefence;
        public bool moor;
        private int moorCounter;
        public bool rainbow;
        private int rainbowCounter;
        public bool flameSea;
        private int flameSeaCounter;

        public bool LightScreen { get; private set; }

        public bool MakeLightScreen(Pokemon maker)
        {
            if (LightScreen)
                return false;
            this.LightScreen = true;
            lightScreenCounter = 5;
            if (maker.GetItem() == Item.LightClay)
                lightScreenCounter = 8;
            log.AppendMsg("EnLightScreen", PlayerName);
            //log.AddText(PlayerName + "的队伍受到了光墙保护！");
            return true;
        }

        public bool Reflect { get; private set; }

        public bool MakeReflect(Pokemon maker)
        {
            if (Reflect)
                return false;
            this.Reflect = true;
            reflectCounter = 5;
            if (maker.GetItem() == Item.LightClay)
                reflectCounter = 8;
            log.AppendMsg("EnReflect", PlayerName);
            //log.AddText(PlayerName + "的队伍受到了反射盾保护！");
            return true;
        }

        public void BreakWall()
        {
            if (LightScreen)
            {
                this.LightScreen = false;
                log.AppendMsg("DeLightScreen", PlayerName);
                //log.AddText(PlayerName + "队伍的光墙消失了！");
            }
            if (Reflect)
            {
                this.Reflect = false;
                log.AppendMsg("DeReflect", PlayerName);
                //log.AddText(PlayerName + "队伍的反射盾消失了！");
            }
        }

        public bool Safeguard { get; private set; }

        public bool MakeSafeguard()
        {
            if (Safeguard)
                return false;
            this.Safeguard = true;
            safeguardCounter = 5;
            log.AppendMsg("EnSafeguard", PlayerName);
            //log.AddText(PlayerName + "的队伍覆盖上了一层防护罩");
            return true;
        }

        public bool Mist { get; private set; }

        public bool MakeMist()
        {
            if (Mist)
                return false;
            this.Mist = true;
            mistCounter = 5;
            log.AppendMsg("EnMist", PlayerName);
            //log.AddText(PlayerName + "的队伍隐藏在雾中");
            return true;
        }

        public bool LuckyChant { get; private set; }

        public bool MakeLuckyChant()
        {
            if (LuckyChant)
                return false;
            this.LuckyChant = true;
            luckyChantCounter = 5;
            log.AppendMsg("EnLuckyChant", PlayerName);
            //log.AddText(PlayerName + "的队伍5回合内不会被命中要害");
            return true;
        }

        public void BreakMist()
        {
            BreakWall();
            this.Safeguard = false;
            this.Mist = false;
            spikesCounter = 0;
            poisonSpikesCounter = 0;
            hideRockCounter = 0;
        }

        public bool WithWind { get; private set; }

        public bool MakeWithWind()
        {
            if (WithWind)
                return false;
            this.WithWind = true;
            withWindCounter = Battle.WithwindTurn;
            log.AppendMsg("EnTailwind", PlayerName);
            //log.AddText(PlayerName + "队伍顺风而行！");
            return true;
        }

        public bool MakeQuickDefence()
        {
            if (!quickDefence)
            {
                quickDefence = true;
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool MakeWideDefence()
        {
            if (!wideDefence)
            {
                wideDefence = true;
                return true;
            }
            else
            {
                return false;
            }
        }

        //public bool MakeMoor()
        //{
        //    if (!moor)
        //    {
        //        moor = true;
        //        moorCounter = 4;
        //        log.AddText(PlayerName + "队伍的场地变成了湿原");
        //    }
        //    else
        //    {
        //        return false;
        //    }
        //}

        //public bool MakeFlameSea()
        //{
        //    if (!flameSea)
        //    {
        //        flameSea = true;
        //        flameSeaCounter = 4;
        //        log.AddText(PlayerName + "队伍的场上出现了彩虹");
        //    }
        //    else
        //    {
        //        return false;
        //    }
        //}

        //public bool MakeRainbow()
        //{
        //    if (!rainbow)
        //    {
        //        rainbow = true;
        //        rainbowCounter = 4;
        //        log.AddText(PlayerName + "队伍的场地变成了火海");
        //    }
        //    else
        //    {
        //        return false;
        //    }
        //}

        #endregion

        #region event

        public event EventHandler PokemonDied;
        public event EventHandler PokemonHPChanged;
        public event EventHandler PokemonStateChanged;
        public event EventHandler PokemonChanged;
        public event EventHandler PokemonImageChanged;

        public void AddPokemonHandler(Pokemon pm)
        {
            pm.Died += PokemonDie;
            pm.HpChanged += PokemonHPChange;
            pm.StateChanged += PokemonStateChange;
            pm.ImageChanged += PokemonImageChange;
        }
        public void RemovePokemonHandler(Pokemon pm)
        {
            pm.Died -= PokemonDie;
            pm.HpChanged -= PokemonHPChange;
            pm.StateChanged -= PokemonStateChange;
            pm.ImageChanged -= PokemonImageChange;
        }
        private void PokemonDie(object sender, EventArgs e)
        {
            IsPokemonDiedThisTurn = true;
            if (PokemonDied != null)
            {
                PokemonDied(sender, EventArgs.Empty);
            }
        }
        private void PokemonHPChange(object sender, EventArgs e)
        {
            if (PokemonHPChanged != null)
            {
                PokemonHPChanged(sender, EventArgs.Empty);
            }
        }
        private void PokemonStateChange(object sender, EventArgs e)
        {
            if (PokemonStateChanged != null)
            {
                PokemonStateChanged(sender, EventArgs.Empty);
            }
        }
        private void PokemonImageChange(object sender, System.EventArgs e)
        {
            if (PokemonImageChanged != null)
            {
                PokemonImageChanged(sender, e);
            }
        }

        #endregion

        public string PlayerName
        {
            get
            {
                return string.Join("&", Teams.Select(t => t.PlayerName).ToArray());
            }
        }

        public bool IsPokemonDiedThisTurn { get; private set; }
        public bool IsPokemonDiedLastTurn { get; private set; }
    }
}
